using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using Magiq.Support;

namespace Magiq.Databases
{
    public abstract class CommandBuilder
    {
        private readonly bool addTypeReference;
        protected const string TypeReferenceName = "__TypeReference__";
        protected CommandBuilder(IOrmAdapter ormAdapter, IQueryable where, bool addTypeReference)
        {
            this.addTypeReference = addTypeReference;
            OrmAdapter = ormAdapter;
            Where = where;
        }

        protected PropertyMapping TypeReferenceProperty { get; private set; }
        protected IQueryable Where { get; private set; }
        protected IOrmAdapter OrmAdapter { get; private set; }
        protected IDbCommand Command { get; private set; }
        protected ITypeMapping Mapping { get; private set; }
        protected string BaseTableName { get; set; }
        protected IEnumerable<string> CalculatedSqlValues { get; private set; }

        protected string From { get; private set; }

        protected SelectStatementInformation Select { get; set; }

        protected void SetCommand(IDbCommand command, IQueryable query)
        {
            Command = command;
            var select = new SelectStatementParser().Parse(Command.CommandText);
            From = select.From;

            var values = OrmAdapter.GetOrderedValuesFrom(select, query);

            BaseTableName = addTypeReference
                                ? values.First().GetUntil(".").Trim()
                                : Mapping.TableName;

            CalculatedSqlValues = addTypeReference ? values.Skip(1) : values;
        }

        public abstract IDbCommand GetCommand();

        protected virtual void Init(Type elementType)
        {
            Mapping = OrmAdapter.GetMappingOf(elementType);
            TypeReferenceProperty = GetTypeReferenceProperty();
        }

        protected virtual PropertyMapping GetTypeReferenceProperty()
        {
            var ids = Mapping.Ids.Select(x => x.PropertyName).ToList();
            return Mapping.Members.First(x => !ids.Contains(x.PropertyName));
        }
    }
}